#include "listcnc.h"
#include <stdlib.h>



typedef struct
{
	int nodenum;
	int nodesize;
	void *Pnodelist;

	int validnodenum;
	int headindex;
	int endindex;


}LISTCNC;


#define LISTISFULL(plist)		((plist->validnodenum == plist->nodenum)?1:0)
#define LISTISEMPTY(plist)		(plist->validnodenum == 0?1:0)
#define LISTMOVEENDBACK(plist)  ((plist->nodenum - 1) == plist->endindex? plist->endindex = 0: plist->endindex+=1);
#define LISTMOVEHEADBACK(plist)	((plist->nodenum - 1) == plist->headindex? plist->headindex = 0: plist->headindex+=1)
#define FORWARDID(plist,id)		((id == 0)?(plist->nodenum - 1):id-1)
#define BACKWARDID(plist,id)    (id == (plist->nodenum -1)?0:id+1);


void* Listcnc_Create(int nodesize, int nodenum)
{
	LISTCNC *ptr = 0;
	ptr = (LISTCNC *)malloc(sizeof(LISTCNC));
	if (ptr)
	{
		ptr->Pnodelist = malloc(nodesize*nodenum);
		if (ptr->Pnodelist)
		{
			ptr->nodenum = nodenum;
			ptr->nodesize = nodesize;
			ptr->validnodenum = 0;
			ptr->headindex = 0;
			ptr->endindex = 0;
		}
		else
		{
			free((void *)ptr);
		}
	}
	return ptr;
}

int Listcnc_Release(void *Plist)
{
	LISTCNC *work_Plist = (LISTCNC *)Plist;
	if (work_Plist)
	{
		if (work_Plist->Pnodelist)
		{
			free(work_Plist->Pnodelist);
		}
		free(work_Plist);
	}
	return 0;
}

int Listcnc_Push(void *Pdata, void *Plist)
{
	LISTCNC *work_Plist = (LISTCNC *)Plist;
	char *work_src;
	char *work_dest;
	if (LISTISFULL(work_Plist)) //if list is full ,return directly
	{
		return LISTCNC_FULL;
	}

	work_src = (char *)Pdata;
	work_dest = (char *)work_Plist->Pnodelist + work_Plist->nodesize * work_Plist->endindex;

	for (int i = 0; i < work_Plist->nodesize; i++)
	{
		*(work_dest + i) = *(work_src + i);
	}
	work_Plist->validnodenum += 1;
	LISTMOVEENDBACK(work_Plist);

	return LISTCNC_OK;
}

int Listcnc_Pop(void *Pdata, void *Plist)
{
	LISTCNC *work_Plist = (LISTCNC *)Plist;
	char *work_src;
	char *work_dest;
	if (LISTISEMPTY(work_Plist))//if list is empty ,return directly
	{
		return LISTCNC_EMPTY;
	}

	if (Pdata) // copy data from the head node of the list into Pdata
	{
		work_dest = (char *)Pdata;
		work_src = (char *)work_Plist->Pnodelist + work_Plist->nodesize * work_Plist->headindex;
		for (int i = 0; i < work_Plist->nodesize; i++)
		{
			*(work_dest + i) = *(work_src + i);
		}
	}
	work_Plist->validnodenum -= 1;
	LISTMOVEHEADBACK(work_Plist);
	return LISTCNC_OK;
}

int Listcnc_GetHeadNode(void *Plist)
{
	return ((LISTCNC *)Plist)->headindex;
}

int Listcnc_GetForward(void *Plist, int id)
{
	return FORWARDID(((LISTCNC *)Plist) , id);
}

int Listcnc_GetBackward(void *Plist, int id)
{
	return BACKWARDID(((LISTCNC *)Plist), id);
}
int Listcnc_GetEndNode(void *Plist)
{
	return ((LISTCNC *)Plist)->endindex;
}
int Listcnc_GetNodeNum(void *Plist)
{
	return ((LISTCNC *)Plist)->nodenum;
}
int Listcnc_GetValidNodeNum(void *Plist)
{
	return ((LISTCNC *)Plist)->validnodenum;
}
void* Listcnc_GetNodeDataPtr(void *Plist, int id)
{
	LISTCNC *work_Plist = (LISTCNC *)Plist;
	if ((id >= 0) && (id < work_Plist->nodenum))
	{
		return ((char *)work_Plist->Pnodelist + work_Plist->nodesize * id);
	}
	return 0;
}